;!function(win){
    "use strict";

    var doc = document,

        config = {
            //记录模块物理路径
            modules:{},
            //记录模块加载状态
            status:{},
            //符合规范的模块请求最长等待秒数
            timeout:10,
            //记录模块自定义事件
            event:{}
        },

        Lucky = function(){
            this.v = '1.0.0';
        },

        getPath = function(){
            var jsPath = doc.currentScript ? doc.currentScript.src : function(){
                var js = doc.scripts,
                    last = js.length - 1,
                    src;
                for(var i = last;i>0;i--){
                    if(js[i].readyState === "interactive"){
                        src = js[i].src;
                        break;
                    }
                }
                return src || js[last].src;
            }();
            return jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
        }(),

        error = function(message){
            win.console && console.error && console.error("Lucky tips:" + message);
        },

        isOpera = typeof win.opera !== 'undefined' && win.opera.toString() === '[object Opera]',

        modules = {
            element:'element',
            form: 'form',
            select: 'forms/select/select',
            maxlength: 'forms/maxlength',
            inputmask: 'forms/inputmask',
            //dialog弹窗
            modal: 'modal/modal',

            bootstrap: 'bootstrap',
            jquery: 'jquery',

            popper: 'components/popper',
            //高性能JavaScript模板引擎
            artTemplate: 'components/artTemplate',
            //菜单插件
            menu: 'components/menu',
            //滚动条插件
            perfectScrollbar: 'components/perfectScrollbar',
            //全屏插件
            screenfull:'components/screenfull',
            //图表组件
            chartist: 'components/charts/chartist.min',
            chartistPluginTooltip: 'components/charts/chartist-plugin-tooltip.min',
            icheck: 'components/icheck/icheck.min',
            //动画
            animate: 'components/animate/appear',
            //弹窗提醒
            sweetalert: 'components/alert/sweetalert',
            toastr: 'components/alert/toastr',
            //星级评价
            raty: 'components/raty/raty',
            //步骤提醒
            hopscotch: 'components/hopscotch/hopscotch',
            //加载状态
            blockUI: 'components/loading/blockUI',
            dropzone: 'components/dropzone/dropzone'
        };

    //记录基础数据
    Lucky.prototype.cache = config;

    //定义模块
    Lucky.prototype.define = function(deps, factory){
        var that = this,
            type = typeof deps === 'function',
            callback = function(){
                var setApp = function(app, exports){
                    lucky[app] = exports;
                    config.status[app] = true;
                };
                typeof factory === 'function' && factory(function(app, exports){
                    setApp(app, exports);
                    config.callback[app] = function(){
                        factory(setApp);
                    }
                });
                return this;
            };
        //如果type是function的话，参数重新初始化
        type && (factory = deps, deps = []);

        that.require(deps, callback);

        return that;
    };

    Lucky.prototype.require = function(apps, callback, exports){
        var that = this,
            dir = config.dir = config.dir ? config.dir : getPath,
            head = doc.getElementsByTagName('head')[0];

        apps = typeof apps === 'string' ? [apps] : apps;

        var item = apps[0],
            timeout = 0;
            exports = exports || [];

        //静态资源host
        config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0];

        //加载完毕
        function onScriptLoad(e, url){
            var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/
            if (e.type === 'load' || (readyRegExp.test((e.currentTarget || e.srcElement).readyState))) {
                config.modules[item] = url;
                head.removeChild(node);
                (function poll(){
                    if(++timeout > config.timeout * 1000 / 4){
                        return error(item + ' is not a valid module');
                    };
                    config.status[item] ? onCallback() : setTimeout(poll, 4);
                }());
            }
        }

        //回调
        function onCallback() {
            exports.push(lucky[item]);
            apps.length > 1 ? that.require(apps.slice(1), callback, exports) : ( typeof callback === 'function' && callback.apply(lucky, exports) );
        }

        if(apps.length === 0){
            return onCallback(), that;
        }

        //首次加载模块
        if(!config.modules[item]){
            var node = doc.createElement('script'),

                //如果是内置模块，则按照 dir 参数拼接模块路径
                //如果是扩展模块，则判断模块路径值是否为 {/} 开头，
                //如果路径值是 {/} 开头，则模块路径即为后面紧跟的字符。
                //否则，则按照 base 参数拼接模块路径
                url = ( modules[item] ? (dir + 'modules/') : (/^\{\/\}/.test(that.modules[item]) ? '' : (config.base || '')) ) + (that.modules[item] || item) + '.js';

            url = url.replace(/^\{\/\}/, '');

            node.async = true;
            node.charset = 'utf-8';
            node.src = url + function(){
                var version = config.version === true ? (config.v || (new Date()).getTime()) : (config.version||'');
                return version ? ('?v=' + version) : '';
            }();

            head.appendChild(node);

            if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){
                node.attachEvent('onreadystatechange', function(e){
                    onScriptLoad(e, url);
                });
            } else {
                node.addEventListener('load', function(e){
                    onScriptLoad(e, url);
                }, false);
            }

            config.modules[item] = url;
        } else {
            (function poll() {
                if(++timeout > config.timeout * 1000 / 4){
                    return error(item + ' is not a valid module');
                };
                (typeof config.modules[item] === 'string' && config.status[item]) ? onCallback() : setTimeout(poll, 4);
            }());
        }

        return that;
    };

    //存储模块的回调
    config.callback = {};

    //重新执行模块的工厂函数
    Lucky.prototype.factory = function(modName){
        if(lucky[modName]){
            return typeof config.callback[modName] === 'function' ? config.callback[modName] : null;
        }
    };

    //全局配置
    Lucky.prototype.config = function (options) {
        options = options || {};
        for(var key in options){
            config[key] = options[key];
        }
        return this;
    };

    Lucky.prototype.modules = function () {
        var clone = {};
        for(var o in modules){
            clone[o] = modules[o];
        }
        return clone;
    }();

    //拓展模块
    Lucky.prototype.extend = function(options){
        var that = this;

        //验证模块是否被占用
        options = options || {};

        for(var o in options){
            if(that[o] || that.modules[o]){
                error('\u6A21\u5757\u540D '+ o +' \u5DF2\u88AB\u5360\u7528');
            } else {
                that.modules[o] = options[o];
            }
        }

        return that;
    };

    Lucky.prototype.getStyle = function(node, name){
        var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null);
        return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name);
    };

    Lucky.prototype.link = function(href, fn, cssname){
        var that = this
            , link = doc.createElement('link')
            , head = doc.getElementsByTagName('head')[0];

        if(typeof fn === 'string') cssname = fn;

        var app = (cssname || href).replace(/\.|\//g, '')
            , id = link.id = 'luckycss-'+app
            , timeout = 0;

        link.rel = 'stylesheet';
        link.href = href + (config.debug ? '?v='+new Date().getTime() : '');
        link.media = 'all';

        if(!doc.getElementById(id)){
            head.appendChild(link);
        }

        if(typeof fn !== 'function') return that;

        //轮询css是否加载完毕
        (function poll(){
            if(++timeout > config.timeout * 1000 / 100){
                return error(href + ' timeout');
            };
            parseInt(that.getStyle(doc.getElementById(id), 'width')) === 1989 ? function(){ fn(); }() : setTimeout(poll, 100);
        }());

        return that;
    };

    //css内部加载器
    Lucky.prototype.addcss = function(firename, fn, cssname){
        return lucky.link(config.dir + 'css/' + firename, fn, cssname);
    };

    //遍历
    Lucky.prototype.each = function(obj, fn){
        var key, that = this;

        if(typeof fn !== 'function') return that;

        obj = obj || [];

        if(obj.constructor === Object){
            for(key in obj){
                if(fn.call(obj[key], key, obj[key])) break;
            }
        } else {
            for(key = 0; key < obj.length; key++){
                if(fn.call(obj[key], key, obj[key])) break;
            }
        }
        return that;
    };

    //路由解析
    Lucky.prototype.router = function(hash){
        var that = this
            , hash = hash || location.hash
            , data = {
            path: []
            , search: {}
            , hash: (hash.match(/[^#](#.*$)/) || [])[1] || ''
        };

        if(!/^#\//.test(hash)) return data; //禁止非路由规范
        hash = hash.replace(/^#\//, '');
        data.href = '/' + hash;
        hash = hash.replace(/([^#])(#.*$)/, '$1').split('/') || [];

        //提取Hash结构
        that.each(hash, function(index, item){
            /^\w+=/.test(item) ? function(){
                item = item.split('=');
                data.search[item[0]] = item[1];
            }() : data.path.push(item);
        });

        return data;
    };

    //本地持久性存储
    Lucky.prototype.data = function(table, settings, storage){
        table = table || 'lucky';
        storage = storage || localStorage;

        if(!win.JSON || !win.JSON.parse) return;

        //如果settings为null，则删除表
        if(settings === null){
            return delete storage[table];
        }

        settings = typeof settings === 'object' ? settings : {key: settings};

        try{
            var data = JSON.parse(storage[table]);
        } catch(e){
            var data = {};
        }

        if('value' in settings) data[settings.key] = settings.value;
        if(settings.remove) delete data[settings.key];
        storage[table] = JSON.stringify(data);

        return settings.key ? data[settings.key] : data;
    };

    //本地会话性存储
    Lucky.prototype.sessionData = function(table, settings){
        return this.data(table, settings, sessionStorage);
    };

    //设备信息
    Lucky.prototype.device = function(key){
        var agent = navigator.userAgent.toLowerCase()

            //获取版本号
            , getVersion = function(label){
                var exp = new RegExp(label + '/([^\\s\\_\\-]+)');
                label = (agent.match(exp)||[])[1];
                return label || false;
            }

            //返回结果集
            , result = {
                os: function(){ //底层操作系统
                    if(/windows/.test(agent)){
                        return 'windows';
                    } else if(/linux/.test(agent)){
                        return 'linux';
                    } else if(/iphone|ipod|ipad|ios/.test(agent)){
                        return 'ios';
                    } else if(/mac/.test(agent)){
                        return 'mac';
                    }
                }()
                , ie: function(){ //ie版本
                    return (!!win.ActiveXObject || "ActiveXObject" in win) ? (
                        (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于ie11并没有msie的标识
                    ) : false;
                }()
                , weixin: getVersion('micromessenger')  //是否微信
            };

        //任意的key
        if(key && !result[key]){
            result[key] = getVersion(key);
        }

        //移动设备
        result.android = /android/.test(agent);
        result.ios = result.os === 'ios';

        return result;
    };

    //自定义模块事件
    Lucky.prototype.onevent = function(modName, events, callback){
        if(typeof modName !== 'string' || typeof callback !== 'function') return this;
        return Lucky.event(modName, events, null, callback);
    };

    //执行自定义模块事件
    Lucky.prototype.event = Lucky.event = function(modName, events, params, fn){
        var that = this,
            result = null,
            //提取事件过滤器字符结构，如：select(xxx)
            filter = events.match(/\((.*)\)$/)||[],
            //获取事件名称，如：form.select
            eventName = (modName + '.'+ events).replace(filter[0], ''),
            //获取过滤器名称,，如：xxx
            filterName = filter[1] || '',
            callback = function(_, item){
                var res = item && item.call(that, params);
                res === false && result === null && (result = false);
            };

        //添加事件
        if(fn){
            config.event[eventName] = config.event[eventName] || {};

            //这里不再对多次事件监听做支持，避免更多麻烦
            //config.event[eventName][filterName] ? config.event[eventName][filterName].push(fn) :
            config.event[eventName][filterName] = [fn];
            return this;
        }

        //执行事件回调
        lucky.each(config.event[eventName], function(key, item){
            //执行当前模块的全部事件
            if(filterName === '{*}'){
                lucky.each(item, callback);
                return;
            }

            //执行指定事件
            key === '' && lucky.each(item, callback);
            key === filterName && lucky.each(item, callback);
        });

        return result;
    };

    win.lucky = new Lucky();

}(window);